import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Request } from 'express';

interface CacheStore {
  get(key: string): any;
  set(key: string, value: any, ttl?: number): void;
  del(key: string): void;
}

@Injectable()
export class CacheInterceptor implements NestInterceptor {
  private cache: Map<string, { value: any; expires: number }> = new Map();

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest<Request>();
    
    // 只缓存 GET 请求
    if (request.method !== 'GET') {
      return next.handle().pipe(
        tap(() => {
          // 写操作后按路径前缀失效相关缓存
          const path = this.getPathWithoutQuery(request.url);
          this.invalidateByPrefix(path);
        })
      );
    }

    const cacheKey = this.generateCacheKey(request);
    const cachedResponse = this.getCachedResponse(cacheKey);

    if (cachedResponse) {
      return of(cachedResponse);
    }

    return next.handle().pipe(
      tap(response => {
        // 缓存 5 分钟
        this.setCachedResponse(cacheKey, response, 300000);
      }),
    );
  }

  private generateCacheKey(request: Request): string {
    const { url, query } = request;
    return `${url}:${JSON.stringify(query)}`;
  }

  private getCachedResponse(key: string): any {
    const cached = this.cache.get(key);
    if (cached && cached.expires > Date.now()) {
      return cached.value;
    }
    
    if (cached) {
      this.cache.delete(key);
    }
    
    return null;
  }

  private setCachedResponse(key: string, value: any, ttl: number): void {
    const expires = Date.now() + ttl;
    this.cache.set(key, { value, expires });
  }

  private getPathWithoutQuery(url: string): string {
    const index = url.indexOf('?');
    return index === -1 ? url : url.substring(0, index);
  }

  private invalidateByPrefix(prefixPath: string): void {
    for (const key of this.cache.keys()) {
      if (key.startsWith(prefixPath)) {
        this.cache.delete(key);
      }
    }
  }
}
